﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Xml.Serialization;
using System.Linq;

namespace SMARTMobile.WinPhone
{
    [XmlRoot("NavigationMap")]
    public class PageNavigationConfiguration
    {
        [XmlIgnore]
        private IDictionary<string, PageMapping> _pageMappings;

        [XmlIgnore]
        private IDictionary<string, ViewModelMapping> _viewModelMappings;

        [XmlArray(ElementName = "Mappings")]
        [XmlArrayItem(ElementName = "Page")]
        public List<PageMapping> Mappings
        {
            get;
            set;
        }

        [XmlArray(ElementName = "ViewModels")]
        [XmlArrayItem(ElementName = "ViewModel")]
        public List<ViewModelMapping> ViewModels
        {
            get;
            set;
        }

        public ViewModelMapping FindViewModel(string modelName)
        {
            ViewModelMapping result;
            _viewModelMappings.TryGetValue(modelName, out result);
            Debug.Assert(null != result, string.Format("PageNavigationConfiguration: Failed to find '{0}' in viewmodel mappings.", modelName));
            return result;
        }

        public PageMapping FindPage(string pagename)
        {
            PageMapping result;
            _pageMappings.TryGetValue(pagename, out result);
            Debug.Assert(null != result, string.Format("PageNavigationConfiguration: Failed to find '{0}' in page mappings.", pagename));
            return result;
        }

        [XmlRoot("Page")]
        public class PageMapping
        {
            [XmlAttribute("name")]
            public string Name { get; set; }

            [XmlAttribute("uri")]
            public string Uri { get; set; }

            [XmlAttribute("query")]
            public string QueryFormat { get; set; }

            public Uri GetUri(int popCount, params string[] args)
            {
                string url = Uri;
                if (!string.IsNullOrWhiteSpace(QueryFormat))
                {
                    if (null != args && args.Length > 0)
                    {
                        url = string.Concat(url, "?", string.Format(QueryFormat, args));
                    }
                }
                else if (null != args && args.Length > 0)
                {
                    string query = args.Aggregate("?", (current, arg) => string.Concat(current, args, "&"));
                    url = string.Concat(url, query);
                }
                if (popCount > 0)
                {
                    if (!url.Contains("?"))
                    {
                        url += "?";
                    }
                    else if (!url.EndsWith("&"))
                    {
                        url += "&";
                    }
                    url += string.Format("pop={0}", popCount);
                }
                Debug.WriteLine(url);
                return new Uri(url, UriKind.Relative);
            }

            public override string ToString()
            {
                return string.Format("{0} : {1}", Name, Uri);
            }
        }

        [XmlRoot("ViewModel")]
        public class ViewModelMapping
        {
            [XmlAttribute("name")]
            public string Name { get; set; }

            [XmlAttribute("assembly")]
            public string Assembly { get; set; }

            [XmlAttribute("type")]
            public string Type { get; set; }

            public object GetObject()
            {
                string typeName = Type;
                if (!string.IsNullOrWhiteSpace(Assembly))
                {
                    typeName = string.Format("{0},{1}", Type, Assembly);
                }
                Type type = System.Type.GetType(typeName);
                return Activator.CreateInstance(type);
            }
        }

        internal void Prepare()
        {
            _viewModelMappings = ViewModels.ToDictionary(p => p.Name);
            _pageMappings = Mappings.ToDictionary(p => p.Name);
        }
    }
}
